/*
 *  This license is based on the BSD license adopted by the Apache Foundation.
 */
package newpeer;

import ejercicios.HelloWorld;
import net.jxta.discovery.DiscoveryEvent;
import net.jxta.discovery.DiscoveryListener;
import net.jxta.discovery.DiscoveryService;
import net.jxta.document.AdvertisementFactory;
import net.jxta.id.ID;
import net.jxta.peergroup.PeerGroup;
import net.jxta.peergroup.PeerGroupID;
import net.jxta.platform.NetworkManager;
import net.jxta.protocol.DiscoveryResponseMsg;

import java.awt.BorderLayout;
import java.io.BufferedReader;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.crypto.Cipher;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.UIManager;
import net.jxta.id.IDFactory;
import net.jxta.peer.PeerID;
import net.jxta.pipe.PipeID;
import net.jxta.pipe.PipeService;
import net.jxta.protocol.PipeAdvertisement;
import net.jxta.socket.JxtaSocket;
import org.farng.mp3.MP3File;
import org.farng.mp3.TagException;
import org.farng.mp3.id3.ID3v1;

/**
 * Illustrates the use of Discovery Service
 * Note this is for illustration purposes and is not meant as a blue-print
 */
public class Peer extends JFrame implements DiscoveryListener {
    //    public static final int PUERTO = 12345;

    public static final int PUERTO = 12345;
    public static final long TAM_PAQUETES = 512;
    private static final String SEPARADOR_MENSAJE = ";";
    public String RUTA_ARCHIVOS_COMPARTIDOS_DESCARGADOS = "C:/temp/";
    public String UPLOADS_GLOBALES = "2";
    private String peerName;
    private PanelBotonesAcciones panelBotonesAcciones;
    private JLabel estadoConexion;
    private transient NetworkManager manager;
    private transient DiscoveryService discovery;
    private transient PeerGroup netPeerGroup = null;
    private PanelArchivos panelArchivos;
    private transient PipeAdvertisement pipeAdv;
    private final static long ITERATIONS = 1000;
    private final static int PAYLOADSIZE = 64 * 1024;
    private PipeID advPipeId;
    //private String ipServidor = "157.253.202.171";
    private String ipServidor = "localhost";
    private ID idpeer;
    private String criterio;
    public final static String SOCKETIDSTR = "urn:jxta:uuid-59616261646162614E5047205032503393B5C2F6CA7A41FBB0F890173088E79404";
    //Lista asociativa en la que la llave el el nombre de archivo y el valor es su advertisement asociado
    private HashMap<String, PipeAdvertisementArchivo> arlist;
    private DialogoBusquedaArchivos instanciaDialogo;
    private String atribuye;
    private Long tamanocriterio;
    private String mensajeNew;
    private String nameArchivo; //El nombre del archivo que este en marcha en ese momento
    private int ipaquete;  // Paquete en el cual se encuentra el archivo a descargar
    private String[] contenidos;
    private HashMap<String, PipeAdvertisementArchivo> listaArchivosRemotos;
    private ThreadPublicacionArchivosCompartidos threadPublicacion;
    public final static String SALIR = "SALIR";
    public final static String CONFIGURACION = "CONFIGURACION";
    private ArrayList<ThreadDescargaArchivo> listaThreadsDescargas;
    private Collection<PipeAdvertisementArchivo> PeerNew;
    private PrivateKey llavePrivada;
    private PublicKey llavePublica;

    public PrivateKey getLlavePrivada() {
        return llavePrivada;
    }

    public PublicKey getLlavePublica() {
        return llavePublica;
    }

    public PanelArchivos getPanelArchivos() {
        return panelArchivos;
    }

    public String getPeerName() {
        return peerName;
    }

    /**
     * Constructor for the Peer
     */
    public Peer(String peerName) {
        this.listaThreadsDescargas = new ArrayList<ThreadDescargaArchivo>();
        this.arlist = new HashMap<String, PipeAdvertisementArchivo>();
        this.peerName = peerName;
        this.setTitle("Documentos Compartidos");
        this.setSize(400, 400);
        this.setLayout(new BorderLayout());

        try {
            AdvertisementFactory.registerAdvertisementInstance(PipeAdvertisementArchivo.getAdvertisementType(), new PipeAdvertisementArchivo.Instantiator());
            manager = new NetworkManager(NetworkManager.ConfigMode.ADHOC, peerName,
                    new File(new File(".cache"), peerName).toURI());
            manager.startNetwork();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }
        netPeerGroup = manager.getNetPeerGroup();
        try {
            PeerGroupID advgroup = IdAssigment.createPeerGroupID("Nuevo Group");
            // Desde la interfaz se le asigna un nombre al peer:
            PipeID advPeerId = IdAssigment.createPipeID(advgroup, peerName);

            String idPeer = peerName;
            PeerServer p = new PeerServer(this, netPeerGroup, advPeerId.toURI().toString());

            Thread threaduno = new Thread(p);

            threaduno.start();
            Thread.currentThread().setName(SocketServer.class.getName() + ".main()");
            AuthenticatePeer(peerName);
        } catch (Throwable e) {
            System.err.println("Failed : " + e);
            e.printStackTrace(System.err);
            System.exit(-1);
        }
        // get the discovery service
        discovery = netPeerGroup.getDiscoveryService();
        discovery.addDiscoveryListener(this);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        inicializarArchivosRemotos();

        pipeAdv = createSocketAdvertisement();



    }

    /**
     * mainer
     *
     * @param args command line args
     */
    public static void main(String args[]) throws IOException {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
        }
        String NamePeer = JOptionPane.showInputDialog("Por favor ingrese el nombre del Peer");
        Peer discoveryServer = new Peer(NamePeer);
        discoveryServer.setVisible(true);
        discoveryServer.iniciapublicacion();
        File[] fRecupera = (new File("C:/temp/Recuperar/" + NamePeer + "/")).listFiles();
        for (int i = 0; i < fRecupera.length; i++) {
            BufferedReader brfile = null;
            try {
                File file = fRecupera[i];
                brfile = new BufferedReader(new FileReader(file));
                String mensaje = brfile.readLine();
                String nombreArchivo = mensaje.split(";")[1];
                String NewArchivo = mensaje.split(";")[2];
                String taman = mensaje.split(";")[3];
                int numpaq = Integer.parseInt(mensaje.split(";")[4]);
                String idpipe = mensaje.split(";")[5];
                ThreadRecuperarDescarga thrnew = new ThreadRecuperarDescarga(nombreArchivo, NewArchivo, file, numpaq, taman, idpipe, discoveryServer, NamePeer);
                thrnew.start();
            } catch (IOException ex) {
                Logger.getLogger(Peer.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    brfile.close();
                } catch (IOException ex) {
                    Logger.getLogger(Peer.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }



    }

    /**
     * create a new pipe adv, publish it for 2 minut network time,
     * sleep for 3 minutes, then repeat
     */
    public void iniciapublicacion() {
        //creacion de Un hilo dedicado a la publicacion de Advertisements en la RED
        this.threadPublicacion = new ThreadPublicacionArchivosCompartidos(discovery, this.peerName);
        threadPublicacion.start();
    }

    public void buscarArchivos(String criterio, String Atributo, DialogoBusquedaArchivos dial, String[] Contenido) throws IOException {
        long waittime = 5 * 1000L;
        atribuye = Atributo;
        this.instanciaDialogo = dial;
        this.criterio = criterio;
        this.contenidos = Contenido;
        arlist.clear();
        try {
            System.out.println("Sending a Discovery Message");
            System.out.println("El criterio de busqueda es: " + criterio);
            System.out.println("Buscando por: " + Atributo);

            // look for any peer
            if (atribuye.equals("X Extension")) {
                tamanocriterio = Long.parseLong(criterio);
                discovery.getRemoteAdvertisements(
                        // no specific peer (propagate)
                        null,
                        // Adv type
                        DiscoveryService.ADV,
                        // Attribute = name
                        "name",
                        // Value = the tutorial
                        "Archivo X",
                        // 1000 advertisement response is all we are looking for
                        1000,
                        // no query specific listener. we are using a global listener
                        null);
            } else if (atribuye.equals("X Contenido")) {
                //JOptionPane.showMessageDialog(null, "BUscando por contenido");
                discovery.getRemoteAdvertisements(
                        // no specific peer (propagate)
                        null,
                        // Adv type
                        DiscoveryService.ADV,
                        // Attribute = name
                        "name",
                        // Value = the tutorial
                        "Archivo X",
                        // 1000 advertisement response is all we are looking for
                        1000,
                        // no query specific listener. we are using a global listener
                        null);
            } //(Atributo.equals("X Archivo"))
            else {
                discovery.getRemoteAdvertisements(
                        // no specific peer (propagate)
                        null,
                        // Adv type
                        DiscoveryService.ADV,
                        // Attribute = name
                        "nombreArchivo",
                        // Value = the tutorial
                        criterio,
                        // 1000 advertisement response is all we are looking for
                        1000,
                        // no query specific listener. we are using a global listener
                        null);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void discoveryEvent(DiscoveryEvent ev) {

        DiscoveryResponseMsg res = ev.getResponse();
        // let's get the responding peer's advertisement
        System.out.println("DISCOVERY_RECIBE [  Got a Discovery Response [" + res.getResponseCount() + " elements]  from peer : " + ev.getSource() + "  ]");

        PipeAdvertisementArchivo adv;
        Enumeration en = res.getAdvertisements();
        if (en != null) {
            while (en.hasMoreElements()) {
                adv = (PipeAdvertisementArchivo) en.nextElement();
                System.out.println(" Peer Information = " + adv.toString());

                if (!arlist.containsKey(adv.getOSName())) {
                    arlist.put(adv.getOSName(), adv);
                }
                idpeer = adv.getID();
                System.out.println(" El ID del archivo del peer= " + idpeer);
                System.out.println("" + adv.getAno());
            }
            if (atribuye.equals("ArchivosRemotos")) {
                listaArchivosRemotos = arlist;
                finalizarConstruccionInterfaz();
            }
            if (atribuye.equals("X Extension")) {
                arlist = darArchivosEnRango(arlist, tamanocriterio);
            }
            if (atribuye.equals("X Contenido")) {
                //JOptionPane.showMessageDialog(null, "Llenando lista por contenido");
                arlist = darArchivosCoincidentesBusquedaContenido(arlist, "mp3", contenidos[0].toLowerCase(), contenidos[1].toLowerCase(), contenidos[2].toLowerCase(), contenidos[3].toLowerCase());
            }
            if (instanciaDialogo != null) {
                instanciaDialogo.actualizarTablaArchivos(arlist);
                //instanciaDialogo.actualizarListaArchivos(arlist);
            }
        }
    }

    public void descargarArchivo(String nombreArchivo, String tamanoArchivo, String idPipe) {
        //  String mensaje = "DESCARGAR_ARCHIVO" + SEPARADOR_MENSAJE + nombreArchivo;
        ThreadDescargaArchivo tda = new ThreadDescargaArchivo(nombreArchivo, tamanoArchivo, idPipe, this, peerName);
        tda.start();
        listaThreadsDescargas.add(tda);
    }

    public void compartirArchivo(File archivoACompartir) throws IOException {
        //Llevar el nuevo Archivo a c:/temp
        ipaquete = 0;
        File nuevoArchivo = new File(RUTA_ARCHIVOS_COMPARTIDOS_DESCARGADOS + archivoACompartir.getName());
        InputStream clienteIn = new FileInputStream(archivoACompartir);
        if (!nuevoArchivo.getParentFile().exists()) {
            //Si no existen las carpetas crearlas
            nuevoArchivo.getParentFile().mkdirs();
        }
        nameArchivo = archivoACompartir.getName();
        long tamArchivo = archivoACompartir.length();
        FileOutputStream fos = new FileOutputStream(nuevoArchivo);
        long tamPaquetes = TAM_PAQUETES;
        long numeroPaquetes = tamArchivo / tamPaquetes;
        long modulo = tamArchivo % tamPaquetes;
        System.out.printf("El modulo es: " + modulo);
        if (tamArchivo < tamPaquetes) {
            byte[] menor = new byte[(int) tamArchivo];
            clienteIn.read(menor);
            fos.write(menor);
        } else {
            for (int i = 0; i < numeroPaquetes; i++) {
                byte[] paq = new byte[(int) tamPaquetes];
                clienteIn.read(paq);
                fos.write(paq);
                ipaquete = i;
                if ((ipaquete == numeroPaquetes - 1) && (modulo == 0)) {
                    mensajeNew = "ESTADO: ARCHIVO COMPARTIDO";
                }
            }
            long loQueFalta = tamArchivo - (numeroPaquetes * tamPaquetes);
            if (loQueFalta > 0) {
                byte[] paq = new byte[(int) loQueFalta];
                clienteIn.read(paq);
                fos.write(paq);
                mensajeNew = "ESTADO: ARCHIVO COMPARTIDO";
            }
        }
        fos.close();
        // Actualizar Interfaz Gráfica
        this.panelArchivos.actualizarArchivos();
        //Crear el nuevo Advertisement
        compartirArchivoEnRed(nuevoArchivo);
        super.repaint();
        pack();
    }

    /**
     * Stops the platform
     */
    public void stop() {
        // Stop JXTA
        manager.stopNetwork();
    }

    public HashMap<String, PipeAdvertisementArchivo> darArchivosRemotos() {
        return listaArchivosRemotos;
    }

    public void abrirDialogoConfiguracionPeer() {
        DialogoConfiguracionPeer dcp = new DialogoConfiguracionPeer(this);
        dcp.setVisible(true);
    }

    public JxtaSocket conectarse(String idPipe) throws IOException {
        long start = System.currentTimeMillis();
        System.out.println("Connecting to the network");
        // JxtaSocket socket = new JxtaSocket();
        PipeID socketID = null;

        try {
            socketID = (PipeID) IDFactory.fromURI(new URI(idPipe));
        } catch (URISyntaxException use) {
            use.printStackTrace();
        }
        PipeAdvertisement pipeAdv1 = (PipeAdvertisement) AdvertisementFactory.newAdvertisement(PipeAdvertisement.getAdvertisementType());

        pipeAdv1.setPipeID(socketID);
        pipeAdv1.setType(PipeService.UnicastType);
        pipeAdv1.setName("Peer to peer socket");
        System.out.println("Saliendo del socket server");
        JxtaSocket socket = new JxtaSocket(netPeerGroup,
                // no specific peerid
                null,
                pipeAdv1,
                // connection timeout: 5 seconds
                6000,
                // reliable connection
                true);

        // get the socket output stream
        return socket;
    }

    public void desconectarse(JxtaSocket socketServidor) {
        try {
            socketServidor.close();
        } catch (IOException ex) {
            JOptionPane.showMessageDialog(this, "Error al desconectar del Servidor", "Error", JOptionPane.ERROR_MESSAGE);
        }
    }

    public void mostrarInfoMP3(String rutaArchivo) {

        if (rutaArchivo.endsWith(".mp3")) {
            try {
                File arch = new File(rutaArchivo);
                MP3File archivoMp3 = new MP3File(arch);
                ID3v1 tagInfo = archivoMp3.getID3v1Tag();
                String albumCancion = tagInfo.getAlbumTitle();
                String artistaCancion = tagInfo.getArtist();
                String nombreCancion = tagInfo.getSongTitle();
                String anoCancion = tagInfo.getYear();
                System.out.println("INFO: " + albumCancion + "\n" + artistaCancion + "\n" + nombreCancion + "\n" + anoCancion + "\n");
            } catch (IOException ex) {
                Logger.getLogger(HelloWorld.class.getName()).log(Level.SEVERE, null, ex);
            } catch (TagException ex) {
                Logger.getLogger(HelloWorld.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public PipeAdvertisement createSocketAdvertisement() {
        PipeID socketID = null;

        try {
            socketID = (PipeID) IDFactory.fromURI(new URI(SOCKETIDSTR));
        } catch (URISyntaxException use) {
            use.printStackTrace();
        }
        PipeAdvertisement advertisement = (PipeAdvertisement) AdvertisementFactory.newAdvertisement(PipeAdvertisement.getAdvertisementType());

        advertisement.setPipeID(socketID);
        advertisement.setType(PipeService.UnicastType);
        advertisement.setName("Peer to peer socket");
        System.out.println("Saliendo del socket server");
        return advertisement;
    }

    public HashMap<String, PipeAdvertisementArchivo> darArchivosEnRango(HashMap<String, PipeAdvertisementArchivo> hashAdvertisementsArchivos, Long tamArchivo) {
        //Comparar los tamaños de los archivos 2MB
        HashMap<String, PipeAdvertisementArchivo> listaArchivosCoincidentes = new HashMap<String, PipeAdvertisementArchivo>();
        PeerNew = arlist.values();
        int sizes = PeerNew.size();
        int j = 0;
        String[][] Kmejores = new String[5][sizes];
        for (PipeAdvertisementArchivo p : PeerNew) {
            String idPipes = p.getIP();
            try {
                JxtaSocket sockK = conectarse(idPipes);
                OutputStream clOut = sockK.getOutputStream();
                InputStream clIn = sockK.getInputStream();
                PrintWriter pw = new PrintWriter(clOut, true);
                //Se debería mandar un tamaño dado por parámetro
                String solicitaK = "SOLICITO_K_MEJORES" + ";" + tamArchivo + ";" + "PeerK";
                System.out.println("Mensaje de Solicitud de k msn: " + solicitaK);
                pw.println(solicitaK);
                BufferedReader br = new BufferedReader(new InputStreamReader(clIn));
                String mensajeIn = br.readLine();
                if (mensajeIn.startsWith("MSN_RANKING")) {
                    for (int i = 1, k = 0; i <= 5; i++, k++) {
                        String msnrankeado = mensajeIn.split(";")[i];
                        if (msnrankeado == null) {
                            msnrankeado = "NONE?0";
                        }
                        Kmejores[k][j] = msnrankeado;
                    }
                }
                System.out.println("Los mejores están: " + Kmejores[0][0]);
            } catch (IOException ex) {
                Logger.getLogger(Peer.class.getName()).log(Level.SEVERE, null, ex);
            }
            j++;
        }

        for (int k = 1; k < sizes; k++) {
            for (int i = 0; i < 5; i++) {
                if (Kmejores[i][k] != null && !Kmejores[i][k].startsWith("null")) {
                    String nameFile = Kmejores[i][k].split("\\?")[0];
                    System.out.println("El mejor con k: " + Kmejores[i][k]);
                    String rankfin = Kmejores[i][k].split("\\?")[1];
                    PipeAdvertisementArchivo pipe = listaArchivosRemotos.get(nameFile);
                    pipe.setHWVendor(rankfin);
                    listaArchivosCoincidentes.put(nameFile, pipe);
                    System.out.println("Se agregó a resultado: " + pipe);
                }
            }
        }
        return listaArchivosCoincidentes;
    }

    public HashMap<String, PipeAdvertisementArchivo> darArchivosCoincidentesBusquedaContenido(HashMap<String, PipeAdvertisementArchivo> hashAdvertisementsArchivos,
            String formatoArchivo, String nombreArtista, String nombreCancion, String nombreAlbum, String anoAlbum) {
        String criterioNombreArtista = "[CRITERIA](.*)", criterioNombreCancion = "[CRITERIA](.*)", criterioNombreAlbum = "[CRITERIA](.*)", criterioAnoAlbum = "[CRITERIA](.*)";
        if (anoAlbum.equals("*") || anoAlbum.equals("")) {
            criterioAnoAlbum = criterioAnoAlbum.replace("[CRITERIA]", "");
        } else {
            criterioAnoAlbum = criterioAnoAlbum.replace("CRITERIA", anoAlbum);
        }
        if (nombreAlbum.equals("*") || nombreAlbum.equals("")) {
            criterioNombreAlbum = criterioNombreAlbum.replace("[CRITERIA]", "");
        } else {
            criterioNombreAlbum = criterioNombreAlbum.replace("CRITERIA", nombreAlbum);
        }
        if (nombreArtista.equals("*") || nombreArtista.equals("")) {
            criterioNombreArtista = criterioNombreArtista.replace("[CRITERIA]", "");
        } else {
            criterioNombreArtista = criterioNombreArtista.replace("CRITERIA", nombreArtista);
        }
        if (nombreCancion.equals("*") || nombreCancion.equals("")) {
            criterioNombreCancion = criterioNombreCancion.replace("[CRITERIA]", "");
        } else {
            criterioNombreCancion = criterioNombreCancion.replace("CRITERIA", nombreCancion);
        }


        Collection<PipeAdvertisementArchivo> advertisementsArchivos = hashAdvertisementsArchivos.values();
        HashMap<String, PipeAdvertisementArchivo> listaArchivosCoincidentes = new HashMap<String, PipeAdvertisementArchivo>();
        for (PipeAdvertisementArchivo advertisementArchivo : advertisementsArchivos) {
            String nombreArchivo = advertisementArchivo.getOSName();
            String nombreArtistaAdvertisement = advertisementArchivo.getNombreArtista().toLowerCase(),
                    nombreCancionAdvertisement = advertisementArchivo.getNombreCancion().toLowerCase(),
                    nombreAlbumAdvertisement = advertisementArchivo.getNombreAlbum().toLowerCase(),
                    anoAlbumAdvertisement = advertisementArchivo.getAno().toLowerCase();
            if (nombreArchivo.toLowerCase().endsWith(formatoArchivo)) {

                /*if (nombreArtista.equalsIgnoreCase(nombreArtistaAdvertisement) || nombreCancion.equalsIgnoreCase(nombreCancionAdvertisement) || nombreAlbum.equals(nombreAlbumAdvertisement) || anoAlbum.equals(anoAlbumAdvertisement)) {
                listaArchivosCoincidentes.put(advertisementArchivo.getOSName(), advertisementArchivo);
                //JOptionPane.showMessageDialog(null, "Agrega " + advertisementArchivo.getOSName() + advertisementArchivo.getAno());
                }*/
                //hacer match por cada criterio

                Pattern patronNombreArtista = Pattern.compile(criterioNombreArtista);
                Matcher matcherPatronNombreArtista = patronNombreArtista.matcher(nombreArtistaAdvertisement);
                Pattern patronNombreCancion = Pattern.compile(criterioNombreCancion);
                Matcher matcherPatronNombreCancion = patronNombreCancion.matcher(nombreCancionAdvertisement);
                Pattern patronNombreAlbum = Pattern.compile(criterioNombreAlbum);
                Matcher matcherPatronNombreAlbum = patronNombreAlbum.matcher(nombreAlbumAdvertisement);
                Pattern patronAnoAlbum = Pattern.compile(criterioAnoAlbum);
                Matcher matcherPatronAnoAlbum = patronAnoAlbum.matcher(anoAlbumAdvertisement);
                if (matcherPatronNombreArtista.matches() && matcherPatronAnoAlbum.matches() && matcherPatronNombreAlbum.matches() && matcherPatronNombreCancion.matches()) {
                    listaArchivosCoincidentes.put(advertisementArchivo.getOSName(), advertisementArchivo);
                }
            }
        }
        return listaArchivosCoincidentes;
    }

    public void recuperarDescarga(File archivoEstado, int numPaqueteRecuperar, String nombreArchivo, String nuevoNombre) {
        PipeAdvertisementArchivo pa = listaArchivosRemotos.get(nombreArchivo);
        pa.setNombreArchivo(nombreArchivo);
        recuperarDescarga(archivoEstado, numPaqueteRecuperar, pa, nuevoNombre);
    }

    private void recuperarDescarga(File archivoEstado, int numPaqueteRecuperar, PipeAdvertisementArchivo pa, String nuevoNombre) {
        ThreadRecuperarDescarga trd = new ThreadRecuperarDescarga(pa.getOSName(), nuevoNombre, archivoEstado, numPaqueteRecuperar, pa.getTamanoArchivo(), pa.getIP(), this, peerName);
        trd.start();
    }

    private void finalizarConstruccionInterfaz() {
        this.panelBotonesAcciones = new PanelBotonesAcciones(this);
        this.panelArchivos = new PanelArchivos(this);
        //conectarConServidor();
        this.add(this.panelArchivos, BorderLayout.CENTER);
        this.add(this.panelBotonesAcciones, BorderLayout.SOUTH);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setJMenuBar(this.crearBarraMenu());
        pack();
        this.setLocationRelativeTo(null);
    }

    private void inicializarArchivosRemotos() {
        atribuye = "ArchivosRemotos";
        discovery.getRemoteAdvertisements(
                // no specific peer (propagate)
                null,
                // Adv type
                DiscoveryService.ADV,
                // Attribute = name
                "name",
                // Value = the tutorial
                "Archivo X",
                // 1000 advertisement response is all we are looking for
                1000,
                // no query specific listener. we are using a global listener
                null);
    }

    public JMenuBar crearBarraMenu() {
        JMenuBar menuBar;
        JMenu menu, submenu;
        JMenuItem menuItem;
        JRadioButtonMenuItem rbMenuItem;
        JCheckBoxMenuItem cbMenuItem;

        //Create the menu bar.
        menuBar = new JMenuBar();

        //Build the first menu.
        menu = new JMenu("Archivo");
        menu.setMnemonic(KeyEvent.VK_A);
        menu.getAccessibleContext().setAccessibleDescription(
                "Permite configurar el Peer");
        menuBar.add(menu);

        ListenerMenuPeer lmp = new ListenerMenuPeer(this);

        /*ImageIcon icon = createImageIcon("images/middle.gif");
        menuItem = new JMenuItem("Both text and icon", icon);
        menuItem.setMnemonic(KeyEvent.VK_B);
        menuItem.addActionListener(lmp);
        menu.add(menuItem);*/

        /*menuItem = new JMenuItem(icon);
        menuItem.setMnemonic(KeyEvent.VK_D);
        menuItem.addActionListener(lmp);
        menu.add(menuItem);*/

        //a group of radio button menu items
        menu.addSeparator();


        //a group of check box menu items
        /*menu.addSeparator();
        cbMenuItem = new JCheckBoxMenuItem("A check box menu item");
        cbMenuItem.setMnemonic(KeyEvent.VK_C);
        cbMenuItem.addItemListener(lmp);
        menu.add(cbMenuItem);

        cbMenuItem = new JCheckBoxMenuItem("Another one");
        cbMenuItem.setMnemonic(KeyEvent.VK_H);
        cbMenuItem.addItemListener(lmp);
        menu.add(cbMenuItem);*/

        //a submenu
        menuItem = new JMenuItem("Configuración...");
        menuItem.addActionListener(lmp);
        menuItem.setActionCommand(CONFIGURACION);

        menu.add(menuItem);

        JMenuItem menuItemSalir = new JMenuItem("Salir");
        menuItemSalir.addActionListener(lmp);
        menuItemSalir.setActionCommand(SALIR);
        menu.add(menuItemSalir);

        //Build second menu in the menu bar.
        /*menu = new JMenu("Another Menu");
        menu.setMnemonic(KeyEvent.VK_N);
        menu.getAccessibleContext().setAccessibleDescription(
        "This menu does nothing");
        menuBar.add(menu);*/

        return menuBar;
    }

    public void SolicitaGuardarEstado(String idPipe) throws IOException {
        try {
            JxtaSocket socketServidor = conectarse(idPipe);
            OutputStream clienteOut = socketServidor.getOutputStream();
            InputStream clienteIn = socketServidor.getInputStream();
            PrintWriter pw = new PrintWriter(clienteOut, true);
            String mensajeguarda = "GUARDE EL ESTADO ACTUAL";
            clienteOut.write(mensajeguarda.getBytes());
            clienteOut.flush();
        } catch (IOException ex) {
            Logger.getLogger(Peer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void EstadoGuardado(String idPipe) throws IOException {
        try {
            JxtaSocket socketCliente = conectarse(idPipe);
            InputStream is = socketCliente.getInputStream();
            OutputStream os = socketCliente.getOutputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String mensajesave = br.readLine();
            if (mensajesave.startsWith("GUARDE EL ESTADO ACTUAL")) {
                mensajeNew = "ARCHIVO EN CURSO" + SEPARADOR_MENSAJE + nameArchivo + SEPARADOR_MENSAJE + "PAQUETE EN CURSO" + SEPARADOR_MENSAJE + ipaquete;
            }
            PrintWriter pw = new PrintWriter(os, true);
            pw.println(mensajeNew);
            is.close();
        } catch (IOException ex) {
            Logger.getLogger(Peer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void compartirArchivoEnRed(File nuevoArchivo) {
        try {
            long lifetime = 60 * 2 * 1000L;
            long expiration = 60 * 2 * 1000L;
            PipeAdvertisementArchivo advTutorial = new PipeAdvertisementArchivo();
            IdAssigment idassigne = new IdAssigment();
            PeerGroupID advgroup = IdAssigment.createPeerGroupID("Nuevo Group");
            // Desde la interfaz se le asigna un nombre al peer:
            PeerID advPeerId = IdAssigment.createPeerID(advgroup, nuevoArchivo.getName());
            PipeID advPipeId = IdAssigment.createPipeID(advgroup, peerName);
            advTutorial.setPipeID(advPipeId);
            advTutorial.setType(PipeService.UnicastType);
            advTutorial.setID(advPeerId);
            ID Laidpeer = advTutorial.getID();
            advTutorial.setName("Archivo X");
            advTutorial.setIP(advTutorial.getPipeID().toString());
            advTutorial.setNombreArchivo(nuevoArchivo.getName());
            advTutorial.setTamanoArchivo(Long.toString(nuevoArchivo.length()));
            advTutorial.setOSArch(System.getProperty("os.arch"));
            advTutorial.setHWArch(System.getProperty("HOSTTYPE", System.getProperty("os.arch")));
            advTutorial.setHWVendor(System.getProperty("java.vm.vendor"));
            if (nuevoArchivo.getName().endsWith(".mp3")) {
                try {
                    MP3File archivoMp3 = new MP3File(nuevoArchivo);
                    ID3v1 tagInfo = archivoMp3.getID3v1Tag();
                    if (tagInfo != null) {
                        String albumCancion = tagInfo.getAlbumTitle();
                        String artistaCancion = tagInfo.getArtist();
                        String nombreCancion = tagInfo.getSongTitle();
                        String anoCancion = tagInfo.getYear();
                        advTutorial.setAno(anoCancion);
                        advTutorial.setNombreAlbum(albumCancion);
                        advTutorial.setNombreArtista(artistaCancion);
                        advTutorial.setNombreCancion(nombreCancion);
                    }
                    //System.out.println("INFO: " + albumCancion + "\n" + artistaCancion + "\n" + nombreCancion + "\n" + anoCancion + "\n");
                } catch (IOException ex) {
                    Logger.getLogger(HelloWorld.class.getName()).log(Level.SEVERE, null, ex);
                } catch (TagException ex) {
                    Logger.getLogger(HelloWorld.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            System.out.println("Publicando advertisement de nuevo archivo compartido :" + lifetime + " expiracion :" + expiration + "La ID del peer: " + Laidpeer);
            //System.out.println(advTutorial.getDocument(MimeMediaType.XMLUTF8).toString());
            System.out.println(advTutorial.getPipeID().toString());
            discovery.publish(advTutorial, lifetime, expiration);
        } catch (IOException ex) {
            Logger.getLogger(Peer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void sacarDeListaDeDescarga(ThreadDescargaArchivo aThis) {
        this.listaThreadsDescargas.remove(aThis);
    }

    private Socket conectarConServidor() {
        try {
            Socket socketServidor = new Socket(ipServidor, PUERTO);
            return socketServidor;
        } catch (UnknownHostException ex) {
            Logger.getLogger(Peer.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Peer.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    private void AuthenticatePeer(String peernombre) throws IOException {
        Socket sockServidor = conectarConServidor();
        OutputStream clienteOut = sockServidor.getOutputStream();
        InputStream clienteIn = sockServidor.getInputStream();

        PrintWriter p = new PrintWriter(clienteOut, true);
        String msnSolCertif = "SOLICITO_CERTIFICADO" + SEPARADOR_MENSAJE + peernombre;
        p.println(msnSolCertif);
        clienteOut.flush();
        BufferedReader br = new BufferedReader(new InputStreamReader(sockServidor.getInputStream()));
        //Formato de resultados RESULTADO: positivo o negativo
        String cadenaResultados = br.readLine();
        if (cadenaResultados.startsWith("CERTIFICADO_EXISTE")) {
            String sTamArchivo = cadenaResultados.split(";")[1];
            long tamArchivo = Long.parseLong(sTamArchivo);
            /*try {*/
            File archivoLlaves = new File("C:/temp/certifica/" + peernombre + ".p12");
            if (!archivoLlaves.getParentFile().exists()) {
                //Si no existen las carpetas crearlas
                archivoLlaves.getParentFile().mkdirs();
            }
            FileOutputStream fos = new FileOutputStream(archivoLlaves);
            long tamPaquetes = TAM_PAQUETES;
            long numeroPaquetes = tamArchivo / tamPaquetes;
            if (tamArchivo < tamPaquetes) {
                byte[] menor = new byte[(int) tamArchivo];
                clienteIn.read(menor);
                fos.write(menor);
            } else {
                for (int i = 0; i < numeroPaquetes; i++) {
                    byte[] paq = new byte[(int) tamPaquetes];
                    clienteIn.read(paq);
                    fos.write(paq);
                }
                long loQueFalta = tamArchivo - (numeroPaquetes * tamPaquetes);
                if (loQueFalta > 0) {
                    byte[] paq = new byte[(int) loQueFalta];
                    clienteIn.read(paq);
                    fos.write(paq);
                }
            }
            procesarLlaves(archivoLlaves);
        } else if (cadenaResultados.startsWith("NOEXISTE_CERTIFICADO")) {
            JOptionPane.showMessageDialog(null,"Usted no tiene permisos para acceder a este grupo","Error ingreso",JOptionPane.ERROR_MESSAGE);
            System.exit(1);
        }
        sockServidor.close();
    }

    private void procesarLlaves(File archivoLlaves) {
        KeyStore keyStore;
        KeyFactory keyFactory = null;

        try {
            //String home = System.getProperty("user.home");
            FileInputStream file_inputstream = new FileInputStream(archivoLlaves);

            keyStore = KeyStore.getInstance("PKCS12");
            keyStore.load(file_inputstream, "compartir".toCharArray());
            
            Key key = keyStore.getKey(peerName, "compartir".toCharArray());
            System.out.println("Key information " + key.getAlgorithm() + " "
                    + key.getFormat());
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key.getEncoded());
            keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
            this.llavePrivada=privateKey;

            Certificate cert = keyStore.getCertificate(peerName);
            //X509EncodedKeySpec keySpec1 = new X509EncodedKeySpec(cert.getPublicKey().getEncoded());
            //PublicKey publicKey = keyFactory.generatePublic(keySpec1);
            PublicKey publicKey = cert.getPublicKey();
            this.llavePublica=publicKey;
            String testString = "A string to be encoded";

            Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            rsaCipher.init(Cipher.ENCRYPT_MODE, this.llavePrivada);
            byte[] encodedBytes = rsaCipher.doFinal(testString.getBytes());
            System.out.println("Encoded byte array length = "
                    + encodedBytes.length + "\nFirst 20 bytes = ");
            for (int i = 0; i < 20; i++) {
                System.out.print(encodedBytes[i] + " ");
            }

            rsaCipher.init(Cipher.DECRYPT_MODE, this.llavePublica);
            byte[] decodedBytes = rsaCipher.doFinal(encodedBytes);
            String output = new String(decodedBytes);
            System.out.println("String after RSA encryption and decryption = "
                    + output);

        } catch (Exception e) {
            System.err.println("Exception:- " + e);
        }
    }
}

